package cn.sq.musicserver.utils;

import cn.sq.musicserver.exception.FileChangeExeception;
import com.alibaba.druid.util.Base64;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Objects;
import java.util.UUID;

/**
 * Created with IntelliJ IDEA.
 * User: SQ
 * Date: 2020/12/11
 * Time: 11:27
 * Description:文件处理工具
 */
@Slf4j
public class FileUtil {

    /**
     * 本地图片转换成base64字符串
     * @param urlPath	下载文件地址
     *  (将图片文件转化为字节数组字符串，并对其进行Base64编码处理)
     * @return
     */
    public static String downloadToBase64(String urlPath) throws IOException {
        // 解决url中可能有中文情况
        System.out.println("url:" + urlPath);
        URL url = new URL(urlPath);
        HttpURLConnection http = (HttpURLConnection) url.openConnection();
        http.setConnectTimeout(3000);
        // 设置 User-Agent 避免被拦截
        http.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)");
        String contentType = http.getContentType();
        System.out.println("contentType: " + contentType);
        // 获取文件大小
        long length = http.getContentLengthLong();
        System.out.println("文件大小：" + (length / 1024) + "KB");
        // 获取文件名
        String fileName = getFileName(http, urlPath);
        InputStream is = http.getInputStream();
// 将图片文件转化为字节数组字符串，并对其进行Base64编码处理
        byte[] data = null;
        // 读取图片字节数组
        try {
            ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
            byte[] buff = new byte[100];
            int rc = 0;
            while ((rc = is.read(buff, 0, 100)) > 0) {
                swapStream.write(buff, 0, rc);
            }
            data = swapStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {

                }
            }
        }
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(data).replaceAll("\r\n", "");
//        return Base64.byteArrayToBase64(data);
    }




    /**
     * base64字符串转换成图片 (对字节数组字符串进行Base64解码并生成图片)
     * @param imgStr		base64字符串
     * @param imgFilePath	指定图片存放路径  （注意：带文件名）
     * @return
     */
    public static boolean Base64ToImage(String imgStr,String imgFilePath) {

        if (StringUtils.isEmpty(imgStr)) // 图像数据为空
            return false;

        try {
            // Base64解码
            byte[] b = Base64Utils.decodeFromString(imgStr);
            for (int i = 0; i < b.length; ++i) {
                if (b[i] < 0) {// 调整异常数据
                    b[i] += 256;
                }
            }

            OutputStream out = new FileOutputStream(imgFilePath);
            out.write(b);
            out.flush();
            out.close();

            return true;
        } catch (Exception e) {
            return false;
        }

    }




    /**
     * description: 使用url 下载远程文件
     *
     * @param urlPath         --- url下载地址
     * @param targetDirectory --- 目标文件夹
     * @return 下载文件名称
     * @throws Exception
     * @version v1.0
     * @author zhangcw
     * @date 2019年9月3日 下午8:29:01
     */
    public static String downloadToFile(String urlPath, String targetDirectory) throws Exception {
        // 解决url中可能有中文情况
        URL url = new URL(urlPath);
        HttpURLConnection http = (HttpURLConnection) url.openConnection();
        http.setConnectTimeout(3000);
        // 设置 User-Agent 避免被拦截
        http.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)");
        String contentType = http.getContentType();
        System.out.println("contentType: " + contentType);
        // 获取文件大小
        long length = http.getContentLengthLong();
        System.out.println("文件大小：" + (length / 1024) + "KB");
        // 获取文件名
        String newName ;
        if (http.getHeaderField("Content-Type").contains("audio")){
            newName=getMusicFileName(http, urlPath,null);
        }else{
            newName=getFileName(http, urlPath);
        }
        InputStream inputStream = http.getInputStream();
        byte[] buff = new byte[1024 * 10];
        File file = new File(targetDirectory, newName);
        OutputStream out = new FileOutputStream(file);
        int len;
        int count = 0; // 计数
        while ((len = inputStream.read(buff)) != -1) {
            out.write(buff, 0, len);
            out.flush();
            ++count;
        }
        System.out.println("count:" + count);
        // 关闭资源
        out.close();
        inputStream.close();
        http.disconnect();
        return newName;
    }

    /**
     * description: 使用url 下载远程文件
     * @param urlPath         --- url资源
     * @param targetDirectory --- 目标文件夹
     * @param name---         自定义的文件名称
     * @return void
     * @throws Exception
     * @version v1.0
     * @author zhangcw
     * @date 2019年9月3日 下午8:29:01
     */
    public static String downloadToFile(String urlPath, String targetDirectory, String name) throws Exception {
        // 解决url中可能有中文情况
        System.out.println("url:" + urlPath);
        URL url = new URL(urlPath);
        HttpURLConnection http = (HttpURLConnection) url.openConnection();
        http.setConnectTimeout(3000);
        // 设置 User-Agent 避免被拦截
        http.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)");
//        String contentType = http.getContentType();
//        System.out.println("contentType: " + contentType);
        // 获取文件大小
        long length = http.getContentLengthLong();
        System.out.println("文件大小：" + (length / 1024) + "KB");
        // 获取文件名
        String fileName;
//        if (http.getHeaderField("Content-Type").contains("audio")){
            fileName=getMusicFileName(http, urlPath,name);
//        }else{
//            fileName=getFileName(http, urlPath);
//        }

        String newName = fileName;
        InputStream inputStream = http.getInputStream();
        byte[] buff = new byte[1024 * 10];
        File file = new File(targetDirectory, newName);
        OutputStream out = new FileOutputStream(file);
        int len;
        int count = 0; // 计数
        while ((len = inputStream.read(buff)) != -1) {
            out.write(buff, 0, len);
            out.flush();
            ++count;
        }
        System.out.println("count:" + count);
        // 关闭资源
        out.close();
        inputStream.close();
        http.disconnect();
        return newName;
    }

    /**
     * description: 获取文件名
     *
     * @param http
     * @param urlPath
     * @return String
     * @throws UnsupportedEncodingException
     * @version v1.0
     * @author w
     * @date 2019年9月3日 下午8:25:55
     */
    private static String getFileName(HttpURLConnection http, String urlPath) throws UnsupportedEncodingException {
        String headerField = http.getHeaderField("Content-Disposition");
        String fileName = null;
        if (null != headerField) {
            String decode = URLDecoder.decode(headerField, "UTF-8");
            fileName = decode.split(";")[1].split("=")[1].replaceAll("\"", "");
            System.out.println("文件名是： " + fileName);
        }
        if (null == fileName) {
            // 尝试从url中获取文件名
            String[] arr = urlPath.split("/");
            fileName = arr[arr.length - 1];
            fileName = fileName.split("\\?")[0];
            System.out.println("url中获取文件名：" + fileName);
        }
        return fileName;
    }
    private static String getMusicFileName(HttpURLConnection http, String urlPath,String name) throws UnsupportedEncodingException {
        String headerField = http.getHeaderField("Content-Type");
        String fileName = null;
        if (null != headerField) {
            String decode = URLDecoder.decode(headerField, "UTF-8");
            fileName = decode.split("/")[1];
            System.out.println("文件名是： " + fileName);
        }
        if (null == fileName) {
            // 尝试从url中获取文件名
            String[] arr = urlPath.split("/");
            fileName = arr[arr.length - 1];
            System.out.println("url中获取文件名：" + fileName);
        }
        if (name==null){
             name = UUID.randomUUID().toString();
        }
        return name+"."+fileName;
    }

    /**
     * 保存文件到本地
     *
     * @param bufferedInputStream
     * @param savePath
     */
    public static void downloadFile(BufferedInputStream bufferedInputStream, String savePath) throws IOException {
        //一次最多读取1k
        byte[] buffer = new byte[1024];
        //实际读取的长度
        int readLenghth;
        //根据文件保存地址，创建文件输出流
        FileOutputStream fileOutputStream = new FileOutputStream(new File(savePath));
        //创建的一个写出的缓冲流
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
        //文件逐步写入本地
        while ((readLenghth = bufferedInputStream.read(buffer, 0, 1024)) != -1) {//先读出来，保存在buffer数组中
            System.out.println(readLenghth);
            bufferedOutputStream.write(buffer, 0, readLenghth);//再从buffer中取出来保存到本地
        }
        //关闭缓冲流
        bufferedOutputStream.close();
        fileOutputStream.close();
        bufferedInputStream.close();
    }


    /**
     * 是否包含字符串
     *
     * @param str  验证字符串
     * @param strs 字符串组
     * @return 包含返回true
     */
    public static boolean inStringIgnoreCase(String str, String... strs) {
        if (str != null && strs != null) {
            for (String s : strs) {
                if (str.equalsIgnoreCase(org.apache.commons.lang3.StringUtils.trim(s))) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 是否包含字符串
     *
     * @param str  验证字符串
     * @param strs 字符串组
     * @return 包含返回true
     */
    public static boolean inString(String str, String... strs) {
        if (str != null && strs != null) {
            for (String s : strs) {
                if (str.equals(org.apache.commons.lang3.StringUtils.trim(s))) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 获取指定文件或文件夹的后缀名
     *
     * @param fileName 文件名称
     * @return
     */
    public static String getFileSuffix(String fileName) {
        return fileName.substring(fileName.lastIndexOf("."));//例如：abc.png  截取后：.png
    }

    /**
     * 获取指定文件或文件夹的后缀名
     *
     * @param file 文件名称
     * @return
     */
    public static String getFileSuffix(File file) {
        String name = file.getName();
        return name.substring(name.lastIndexOf("."));//例如：abc.png  截取后：.png
    }

    /**
     * 检查指定文件是否符合视频格式规定
     *
     * @param file 文件名称
     * @return
     */
    public static boolean checkFileType(File file) {
        return CmdUtils.inStringIgnoreCase(CmdUtils.getFileSuffix(file.getName()));
    }

    /**
     * multipartFile转File
     *
     * @param multipartFile spring 文件流
     * @param outfilepath   生成文件地址
     * @return 是否成功
     * @throws IOException
     */
    public static boolean multipartFileToFile(MultipartFile multipartFile, String outfilepath) throws FileChangeExeception {
        try {
            File file = new File(outfilepath);
            boolean isCreateSuccess = file.createNewFile();
            if (isCreateSuccess) {
                FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), file);
            } else {
                throw new FileChangeExeception("创建File文件异常");
            }
        } catch (IOException e) {
            e.printStackTrace();
            log.error(e.getMessage());
            throw new FileChangeExeception("multipartFile转File异常");
        }
        return true;
    }

    public static void download(String filename, HttpServletResponse res) throws IOException {
        // 发送给客户端的数据
        OutputStream outputStream = res.getOutputStream();
        byte[] buff = new byte[1024];
        BufferedInputStream bis = null;
        // 读取filename
        bis = new BufferedInputStream(new FileInputStream(new File(filename)));
        int i = bis.read(buff);
        while (i != -1) {
            outputStream.write(buff, 0, buff.length);
            outputStream.flush();
            i = bis.read(buff);
        }
    }




}
